﻿// ----------------------------------------------------------------------------------
// <copyright file="ContextContainerTest.cs" company="Christopher Hines">
// Copyright (c) 2012 All Right Reserved
// </copyright>
// <author>Chris Hines</author>
// <date>2012-03-28</date>
// <summary>
//     General unit tests
// </summary>
// ----------------------------------------------------------------------------------

namespace Copperfield.Tests
{
    using System.Linq;

    using Copperfield;
    using Copperfield.Fakes;
    using Copperfield.Sdk;

    using FluentAssertions;

    using Microsoft.VisualStudio.TestTools.UnitTesting;

    using StructureMap;

    /// <summary>
    /// General unit tests
    /// </summary>
    [TestClass]
    public class ContextContainerTest
    {
        /// <summary>
        /// Gets or sets the context manager
        /// </summary>
        /// <value>
        /// The context manager
        /// </value>
        private static ContextManagerBase<UnitTestContext> contextManager;

        /// <summary>
        /// Initializes the test class
        /// </summary>
        /// <param name="testContext">
        /// The TestContext object
        /// </param>
        [ClassInitialize]
        public static void MyClassInitialize(TestContext testContext)
        {
            InitializeStructureMap();
            contextManager = ObjectFactory.GetInstance<ContextManagerBase<UnitTestContext>>();
        }

        /// <summary>
        /// A unit test for getting a collection of objects based on context
        /// directly from the framework's container
        /// </summary>
        [TestMethod]
        public void Direct_Container_Collection_Request_FakeB_and_FakeC_Test()
        {
            SetContext(Letter.C, Number.Two);

            var actual = ContextContainer.GetAllInstances<IFake, UnitTestContext>();

            actual.Count().Should().Be(2);
            actual.Should().OnlyContain(x => x is FakeB || x is FakeC);
        }

        /// <summary>
        /// A unit test for getting a collection of objects based on context
        /// directly from the framework's container
        /// </summary>
        [TestMethod]
        public void Direct_Container_Collection_Request_FakeD_and_FakeE_Test()
        {
            SetContext(Letter.B, Number.Two);

            var actual = ContextContainer.GetAllInstances<IFake, UnitTestContext>();

            actual.Count().Should().Be(2);
            actual.Should().OnlyContain(x => x is FakeD || x is FakeE);
        }

        /// <summary>
        /// A unit test for getting a collection of objects based on context
        /// by calling StructureMap's ObjectFactory directly.
        /// </summary>
        [TestMethod]
        public void StructureMap_ObjectFactory_Request_FakeB_and_FakeC_Test()
        {
            SetContext(Letter.C, Number.Two);

            var actual = ObjectFactory.GetInstance<IContextualCollection<IFake>>();

            actual.Count().Should().Be(2);
            actual.Should().OnlyContain(x => x is FakeB || x is FakeC);
        }

        /// <summary>
        /// A unit test for getting a collection of objects based on context
        /// by calling StructureMap's ObjectFactory directly.
        /// </summary>
        [TestMethod]
        public void StructureMap_ObjectFactory_Request_FakeD_and_FakeE_Test()
        {
            SetContext(Letter.B, Number.Two);

            var actual = ObjectFactory.GetInstance<IContextualCollection<IFake>>();

            actual.Count().Should().Be(2);
            actual.Should().OnlyContain(x => x is FakeD || x is FakeE);
        }

        /// <summary>
        /// A unit test for getting a collection of a plugin type using 
        /// constructor injection and StructureMap
        /// </summary>
        [TestMethod]
        public void StructureMap_Ctor_Injection_Collection_FakeB_and_FakeC_Test()
        {
            SetContext(Letter.C, Number.Two);

            var obj = ObjectFactory.GetInstance<GenericConstructorInjectionHelper<IContextualCollection<IFake>>>();

            var actual = obj.GetObject().ToList();

            actual.Count().Should().Be(2);
            actual.Should().OnlyContain(x => x is FakeB || x is FakeC);
        }

        /// <summary>
        /// A unit test for getting a collection of a plugin type using 
        /// constructor injection and StructureMap
        /// </summary>
        [TestMethod]
        public void StructureMap_Ctor_Injection_Collection_FakeD_and_FakeE_Test()
        {
            SetContext(Letter.B, Number.Two);

            var obj = ObjectFactory.GetInstance<GenericConstructorInjectionHelper<IContextualCollection<IFake>>>();

            var actual = obj.GetObject().ToList();

            actual.Count().Should().Be(2);
            actual.Should().OnlyContain(x => x is FakeD || x is FakeE);
        }

        /// <summary>
        /// Sets the context
        /// </summary>
        /// <param name="channel">
        /// The channel value
        /// </param>
        /// <param name="lineOfBusiness">
        /// The line of business value
        /// </param>
        private static void SetContext(Letter channel, Number lineOfBusiness)
        {
            var context = contextManager.GetContext() ?? new UnitTestContext();

            context.Number = lineOfBusiness;
            context.Letter = channel;

            contextManager.SetContext(context);
        }

        /// <summary>
        /// Initializes StructureMap
        /// </summary>
        private static void InitializeStructureMap()
        {
            ObjectFactory.Initialize(
                x =>
                    {
                        x.Scan(
                            scan =>
                                {
                                    scan.TheCallingAssembly();
                                    scan.WithDefaultConventions();
                                });

                        x.EnableContextBasedResolution();
                        x.For<ContextManagerBase<UnitTestContext>>().Use<NonWebContextManager<UnitTestContext>>();
                        x.For(typeof(GenericConstructorInjectionHelper<>)).Use(typeof(GenericConstructorInjectionHelper<>));
                    });
        }
    }
}
